package com.ifcar.app.util;

import java.io.IOException;
import java.io.InputStream;
import java.net.SocketTimeoutException;
import java.net.URI;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.concurrent.TimeUnit;
import java.util.zip.GZIPInputStream;


import org.apache.commons.httpclient.HttpStatus;
import org.apache.http.Header;
import org.apache.http.HeaderElement;
import org.apache.http.HeaderElementIterator;
import org.apache.http.HttpEntity;
import org.apache.http.HttpEntityEnclosingRequest;
import org.apache.http.HttpException;
import org.apache.http.HttpRequest;
import org.apache.http.HttpRequestInterceptor;
import org.apache.http.HttpResponse;
import org.apache.http.HttpResponseInterceptor;
import org.apache.http.HttpVersion;
import org.apache.http.NoHttpResponseException;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpRequestRetryHandler;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.conn.ClientConnectionManager;
import org.apache.http.conn.ConnectTimeoutException;
import org.apache.http.conn.ConnectionKeepAliveStrategy;
import org.apache.http.conn.params.ConnManagerParams;
import org.apache.http.conn.params.ConnPerRouteBean;
import org.apache.http.conn.scheme.PlainSocketFactory;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.entity.HttpEntityWrapper;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
import org.apache.http.message.BasicHeaderElementIterator;
import org.apache.http.params.HttpProtocolParams;
import org.apache.http.params.HttpParams;
import org.apache.http.protocol.ExecutionContext;
import org.apache.http.protocol.HTTP;
import org.apache.http.protocol.HttpContext;
import org.apache.http.util.EntityUtils;

import com.jakewharton.DiskLruCache;

import android.content.Context;
import android.util.Log;

/**
 * 单例多线程http客户端处理类
 * @author zhangyp
 *
 */
public class NeteaseHttpClient {
    private static int maxTotalConnections = 10;
    private static int maxPerRouter = 20;
    private static String TAG = "NeteaseHttpClient";
    private static DiskLruCache cache;
    private static final int VERSION = 201202;
    private static final int ENTRY_METADATA = 0;
    private static final int ENTRY_BODY = 1;
    private static final int ENTRY_COUNT = 2;
    private static final long httpCacheSize = 10 * 1024 * 1024; // 10 MiB
    private static final String LAST_MODIFIED = "Last-Modified";
    private static final String IF_MODIFIED_SINCE = "If-Modified-Since";
    private static final int INT_MODIFIED_SINCE = 0;
    private static final int INT_ENTRY = 1;
    private static int retryCount = 1;//重连次数
    private static long connection_timeout = 60*1000;
    private static DefaultHttpClient httpclient = null;
    /**
     * 构造函数
     */
    private NeteaseHttpClient() {
    }
    
    
    /**
     * 打印http响应头
     * @param headers
     */
    public static void printHeader(Header[] headers){
        
        if(null!=headers){
            
            for(int index=0;index<headers.length;index++){
                
                Header one = headers[index];
                print(one.getName()+":"+one.getValue());
            }
        }
    }
    
    private static void print(String msg){
        Log.i(TAG , msg);
    }
    
    /**
     * 获得HTTP请求缓存对象
     * @param mContext
     * @return
     */
    public static DiskLruCache getCache(Context mContext){
         initCache(mContext);
         return cache;
    }
    
    public static void removeCache(Context mContext,String url){
        try {
            DiskLruCache cache = NeteaseHttpClient.getCache(mContext);
            String key = NeteaseHttpClient.getkeyByURI(url);
            cache.remove(key);
            cache.flush();
        } catch (Exception e1) {
            // TODO Auto-generated catch block
            e1.printStackTrace();
        }
    }
    
    /**
     * 初始化缓存
     * @param mContext
     */
    public static void initCache(Context mContext){
        
        try {
            if(null==cache){
                cache = DiskLruCache.open(mContext.getCacheDir(), VERSION, ENTRY_COUNT, httpCacheSize);
            }
            if(cache.isClosed()){
                cache = DiskLruCache.open(mContext.getCacheDir(), VERSION, ENTRY_COUNT, httpCacheSize);
            }
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
       
    }

    /**
     * 获得httpclient对象 其是一个单例对象
     * @param params
     * @return
     */
    public static synchronized DefaultHttpClient getHttpClient(HttpParams params) {
        if (null== httpclient) {
          
            // 设置我们的HttpClient支持HTTP和HTTPS两种模式
            SchemeRegistry schReg =new SchemeRegistry();
            schReg.register(new Scheme("http", PlainSocketFactory
                    .getSocketFactory(), 80));
            schReg.register(new Scheme("https", SSLSocketFactory
                    .getSocketFactory(), 443));
            ConnManagerParams.setTimeout(params, connection_timeout);
            ConnPerRouteBean connPerRoute = new ConnPerRouteBean(maxPerRouter);
            ConnManagerParams.setMaxConnectionsPerRoute(params, connPerRoute);
            ConnManagerParams.setMaxTotalConnections(params, maxTotalConnections);
            HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
            // 使用线程安全的连接管理来创建HttpClient
            ClientConnectionManager conMgr =new ThreadSafeClientConnManager(params, schReg);
            httpclient =new DefaultHttpClient(conMgr, params);
            
          //GZIP传输
            httpclient.addRequestInterceptor(new HttpRequestInterceptor() {
                @Override
                public void process(final HttpRequest request, final HttpContext context) throws HttpException,
                        IOException {
                    if (!request.containsHeader("Accept-Encoding")) {
                        request.addHeader("Accept-Encoding", "gzip");
                    }
                }
            });
            httpclient.addResponseInterceptor(new HttpResponseInterceptor() {
                @Override
                public void process(final HttpResponse response, final HttpContext context) throws HttpException,
                        IOException {
                    HttpEntity entity = response.getEntity();
                    if(null!=entity){
                        Header ceheader = entity.getContentEncoding();
                        if (ceheader != null) {
                            HeaderElement[] codecs = ceheader.getElements();
                            for (int i = 0; i < codecs.length; i++) {
                                if (codecs[i].getName().equalsIgnoreCase("gzip")) {
                                    response.setEntity(new GzipDecompressingEntity(response.getEntity()));
                                    return;
                                }
                            }
                        }
                    }
                    
                }
            });
            //自动重试
            HttpRequestRetryHandler myRetryHandler = new HttpRequestRetryHandler() {
                @Override
                public boolean retryRequest(IOException exception, int executionCount, HttpContext context) {
                    boolean rtn = true;
                    if (executionCount > retryCount) { //重连retryCount+1次之后 不再重试
                        rtn = false;
                    } else if (exception instanceof NoHttpResponseException
                            || exception instanceof SocketTimeoutException
                            || exception instanceof ConnectTimeoutException) {
                        rtn = true; //只针对特定的异常重试
                    } else {
                        HttpRequest request = (HttpRequest) context.getAttribute(ExecutionContext.HTTP_REQUEST);
                        boolean idempotent = !(request instanceof HttpEntityEnclosingRequest);
                        rtn = idempotent; // 只针对幂等的HTTP方法(GET HEAD)重试
                    }
                    return rtn;
                }
            };
            httpclient.setHttpRequestRetryHandler(myRetryHandler);
            //持久连接策略
            httpclient.setKeepAliveStrategy(new ConnectionKeepAliveStrategy() {
                @Override
                public long getKeepAliveDuration(HttpResponse response, HttpContext context) {
                    HeaderElementIterator iterator = new BasicHeaderElementIterator(response
                            .headerIterator(HTTP.CONN_KEEP_ALIVE)); // 兑现Header里的“keep-alive” （HTTP1.1中）
                    while (iterator.hasNext()) {
                        HeaderElement header = (HeaderElement) iterator.next();
                        String param = header.getName();
                        String value = header.getValue();
                        if (value != null && param.equalsIgnoreCase("timeout")) {
                            try {
                                return Long.parseLong(value) * 1000;
                            } catch (Exception e) {
                                return 20 * 1000;
                            }
                        }
                    }
                    return 20 * 1000; //默认保持20秒的连接
                }
            });
            
        }else{
            httpclient.setParams(params);  
        }
        return httpclient;
    }
    
    /**
     * 释放httpclient对象，目前不能使用
     * return void
     */
    public static void releaseNeteaseHttpClient(){
        if(null!=httpclient){
            ClientConnectionManager conmanager = httpclient.getConnectionManager();
            if(null!=conmanager){
                conmanager.closeExpiredConnections();
                conmanager.closeIdleConnections(20, TimeUnit.SECONDS);
            }
           
        }
    }
    
    /**
     * 对httprequest支持缓存模式
     * @param request
     * @return String
     */
    public static String getforCache(HttpGet request){
        if(null!=request){
            return handlerStatusCode(request);
        }else{
            return null;
        }
    }
    
    /**
     * 获得key
     * @param uri
     * @return
     */
    public static String getkeyByURI(String uri){
        try{
            return uriToKey(uri);
        }catch(Exception ex){
            return uri;
        }
    }
    /**
     * httprequest请求缓存处理
     * @param request
     * @return String
     */
    private static String handlerStatusCode(HttpGet request){
        
        try {
            
            String uri = request.getURI().toString();
            
            String key = uriToKey(uri);
           
            DiskLruCache.Snapshot snapshot= cache.get(key);
            if(null!=snapshot){
                String ims = snapshot.getString(INT_MODIFIED_SINCE);
                if(null!=ims){
                    request.setHeader(IF_MODIFIED_SINCE, ims);
                }
            }
            HttpResponse httpResponse = httpclient.execute(request);
            int statuscode = httpResponse.getStatusLine().getStatusCode();
            String rest = null;
           
           
            switch(statuscode){
                case HttpStatus.SC_OK:
                    HttpEntity entity = null;
                    entity = httpResponse.getEntity();
                    if(null!=entity){  
                        rest = EntityUtils.toString(entity,HTTP.UTF_8);
                        try {
                            DiskLruCache.Editor editor = null;
                            editor = cache.edit(key);
                           
                            Header last_modify_header = httpResponse.getLastHeader(LAST_MODIFIED);
                            if(null==last_modify_header){
                                cache.remove(key);
                            }else{
                                if(null!=rest && !"".equalsIgnoreCase(rest)){
                                    if(null!=editor){
                                        editor.set(INT_MODIFIED_SINCE, last_modify_header.getValue());
                                        editor.set(INT_ENTRY, rest);
                                        editor.commit();
                                    }
                                   
                                }else{
                                    cache.remove(key);
                                }
                                
                            }
                            cache.flush();
                        } catch (Exception e) {
                            
                            e.printStackTrace();
                        }
                    }
                    
                    break;
                case HttpStatus.SC_NOT_MODIFIED:
                    if(null!=snapshot){
                        rest = snapshot.getString(INT_ENTRY);
                        
                    }else{
                        cache.remove(key);
                        cache.flush();
                    }
                    break;
                default:
                    
                    break;
            }
            
            return rest;
            
        } catch (ClientProtocolException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return null;
    }
    
    /**
     * 将URL转换为缓存所需要的key值
     * @param uri
     * @return String
     */
    private static String uriToKey(String uri) {
        try {
            MessageDigest messageDigest = MessageDigest.getInstance("MD5");
            byte[] md5bytes = messageDigest.digest(Strings.getBytes(uri,Charsets.UTF_8));
            return Strings.bytesToHexString(md5bytes, false);
        } catch (NoSuchAlgorithmException e) {
            throw new AssertionError(e);
        }
    }
    
    /**
     * GZIP 解压类.
     * @author zhangyp
     */
    public static class GzipDecompressingEntity extends HttpEntityWrapper {

        public GzipDecompressingEntity(final HttpEntity entity) {
            super(entity);
        }

        @Override
        public InputStream getContent() throws IOException, IllegalStateException {
            // the wrapped entity's getContent() decides about repeatability
            InputStream wrappedin = wrappedEntity.getContent();
            return new GZIPInputStream(wrappedin);
        }

        @Override
        public long getContentLength() {
            // ungzipped content 长度是未知的
            return -1;
        }

    }
}
